/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package xenon3d.scene;

import javax.media.opengl.GL2;

/**
 * The LineAttributes object defines all attributes that apply to line
 * primitives.
 * 
 * @author Volker Everts
 * @version 0.1 - 10.12.2009: Created
 * @version 0.2 - 12.11.2011: Adapted
 */
public class LineAttributes extends Attributes {

    // <editor-fold defaultstate="collapsed" desc=" Static Attributes ">
    
    /** The default line attributes. */
    static final LineAttributes DEFAULT = new LineAttributes();
    
    /** The last active LineAttributes. */
    static LineAttributes last = DEFAULT;
    
    // </editor-fold>
    
    // <editor-fold defaultstate="collapsed" desc=" Public Enumerations ">
    
    /**
     * An enumeration of all line patterns.
     */
    public static enum LinePattern {
        
        /** The solid line pattern (1111 1111 1111 1111). */
        Solid (0xffff),
        
        /** The dash line pattern (0000 0000 1111 1111).*/
        Dash (0x00ff),
        
        /** The dot line pattern (0000 0001 0000 0001). */
        Dot (0x0101),
        
        /** The dash dot line pattern (0000 1000 0111 1111). */
        DashDot (0x087f),
        
        /** The user defined line pattern. */
        User (0x0000);
        
        /** The line pattern value. */
        private short value;
        
        /**
         * Creates a new LinePattern.
         * @paran value the line pattern value
         */
        LinePattern(int value) {
            this.value = (short) value;
        }
        
        /**
         * Returns the line pattern value.
         * @return the line pattern value
         */
        public short value() {
            return value;
        }
        
    } // end enum LinePattern
    
    // </editor-fold>
    
    // <editor-fold defaultstate="collapsed" desc=" Private Fields ">
    
    /** The line width. */
    private float width = 1.0f;
    
    /** The antialiasing flag. */
    private boolean antialiasing = false;
    
    /** The line pattern to use. */
    private LinePattern pattern = LinePattern.Solid;
    
    /** The line pattern scale factor. */
    private short factor = (short) 1;

    // </editor-fold>
    
    // <editor-fold defaultstate="collapsed" desc=" Initialization ">
    
    /**
     * Creates a new LineAttributes object using default parameter settings.
     * The default settings are:<p>
     * <ul>
     * <li>line width: 1.0f</li>
     * <li>pattern: LinePattern.Solid</li>
     * <li>antialiasing: false</li>
     * <li>scale factor: 1</li>
     * </ul>
     */
    public LineAttributes() {}

    /**
     * Creates a new LineAttributes object using the specified line width,
     * pattern and antialiasing flag.
     * @param width the line width
     * @param pattern the line pattern
     * @param antialiasing true, if line antialiasing is enabled
     */
    public LineAttributes(float width, LinePattern pattern, boolean antialiasing) {
        this.width = width;
        this.pattern = pattern;
        this.antialiasing = antialiasing;
    }
    
    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc=" Public Properties ">
    
    /**
     * Sets line width attribute.
     * @param width the new line width
     */
    public final void setLineWidth(float width) {
        if (width < 0.0f) throw new IllegalArgumentException();
        checkCapability(Capability.AllowLineAttributesWrite);
        this.width = width;
    }
    
    /**
     * Returns the line width attribute.
     * @return the current line width
     */
    public final float getLineWidth() {
        return width;
    }
    
    /**
     * Sets whether line antialiasing should be enabled.
     * @param enable if true, line antialiasing is enabled
     */
    public final void setLineAntialiasing(boolean enable) {
        checkCapability(Capability.AllowLineAttributesWrite);
        antialiasing = enable;
    }
    
    /**
     * Returns the current antialiasing state.
     * @return true, if line antialiasing is enabled
     */
    public final boolean isLineAntialiasing() {
        return antialiasing;
    }
    
    /**
     * Sets the line pattern attribute.
     * @param pattern the new line pattern
     */
    public final void setLinePattern(LinePattern pattern) {
        checkCapability(Capability.AllowLineAttributesWrite);
        if (pattern == null) throw new IllegalArgumentException();
        this.pattern = pattern;
    }
    
    /**
     * Returns the line pattern attribute.
     * @return the current line pattern attribute
     */
    public final LinePattern getLinePattern() {
        return pattern;
    }
    
    /**
     * Sets the user line pattern.
     * @param pattern the user line pattern value
     */
    public final void setUserLinePattern(short pattern) {
        checkCapability(Capability.AllowLineAttributesWrite);
        this.pattern = LinePattern.User;
        this.pattern.value = pattern;
    }
    
    /**
     * Sets the line pattern scale factor.
     * @param factor the new line pattern scale factor
     */
    public final void setLinePatternScaleFactor(int factor) {
        checkCapability(Capability.AllowLineAttributesWrite);
        if (factor < 1 || factor > 15) throw new IllegalArgumentException();
        this.factor = (short) factor;
    }
    
    /**
     * Returns the line pattern scale factor.
     * @return the current line pattern scale factor
     */
    public final int getLinePatternScaleFactor() {
        return (int) factor;
    }
    
    // </editor-fold>
    
    // <editor-fold defaultstate="collapsed" desc=" Package Private Methods (OpenGL) ">
    
    @Override
    void apply(GL2 gl) {
        if (this == last) return;
        if (width != last.width) gl.glLineWidth(width);
        if (antialiasing != last.antialiasing) {
            if (antialiasing) gl.glEnable(GL2.GL_LINE_SMOOTH);
            else gl.glDisable(GL2.GL_LINE_SMOOTH);
        }
        if (pattern != last.pattern || factor != last.factor) {
            if (pattern == LinePattern.Solid) gl.glDisable(GL2.GL_LINE_STIPPLE);
            else {
                gl.glEnable(GL2.GL_LINE_STIPPLE);
                gl.glLineStipple(factor, pattern.value);
            }
        }
        last = this;
    }
    
    // </editor-fold>
    
} // end LineAttributes